﻿
namespace Leek.Persistence
{
    public abstract class FilterExpression
    {
        protected internal FilterExpression()
        { }
    }


    public sealed class FilterByProperty : FilterExpression //TODO: Use DomainObjectProperty here?
    {
        public enum ComparisonOperations
        {
            Equal,
            GreaterThan,
            GreaterThanOrEqual,
            LessThan,
            LessThanOrEqual,
            NotEqual
        }


        private readonly string _propertyName;
        private readonly ComparisonOperations _comparisonOperation;
        private readonly object _comparisonValue;


        public string PropertyName
        {
            get { return _propertyName; }
        }

        public ComparisonOperations ComparisonOperation
        {
            get { return _comparisonOperation; }
        }

        public object ComparisonValue
        {
            get { return _comparisonValue; }
        }


        internal FilterByProperty(string propertyName,
            ComparisonOperations comparisonOperation, object comparisonValue)
        {
            _propertyName = propertyName;
            _comparisonOperation = comparisonOperation;
            _comparisonValue = comparisonValue;
        }
    }


    public sealed class BinaryExpression : FilterExpression
    {
        public enum LogicalOperations
        {
            And,
            Not, //TODO: Is this binary!?!?
            Or
        }


        private readonly LogicalOperations _logicalOperation;
        private readonly FilterExpression _leftTerm;
        private readonly FilterExpression _rightTerm;


        public LogicalOperations LogicalOperation
        {
            get { return _logicalOperation; }
        }

        public FilterExpression LeftTerm
        {
            get { return _leftTerm; }
        }

        public FilterExpression RightTerm
        {
            get { return _rightTerm; }
        }


        internal BinaryExpression(LogicalOperations logicalOperation,
            FilterExpression leftTerm, FilterExpression rightTerm)
        {
            _logicalOperation = logicalOperation;
            _leftTerm = leftTerm;
            _rightTerm = rightTerm;
        }
    }


    public static class Filter
    {
        public static FilterByProperty Equal(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.Equal, comparisonValue);
        }

        public static FilterByProperty GreaterThan(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.GreaterThan, comparisonValue);
        }

        public static FilterByProperty GreaterThanOrEqual(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.GreaterThanOrEqual, comparisonValue);
        }

        public static FilterByProperty LessThan(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.LessThan, comparisonValue);
        }

        public static FilterByProperty LessThanOrEqual(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.LessThanOrEqual, comparisonValue);
        }

        public static FilterByProperty NotEqual(string propertyName, object comparisonValue)
        {
            return new FilterByProperty(propertyName, FilterByProperty.ComparisonOperations.NotEqual, comparisonValue);
        }


        public static BinaryExpression And(this FilterExpression leftTerm, FilterExpression rightTerm)
        {
            return new BinaryExpression(BinaryExpression.LogicalOperations.And, leftTerm, rightTerm);
        }

        public static BinaryExpression Not(this FilterExpression leftTerm, FilterExpression rightTerm)
        {
            return new BinaryExpression(BinaryExpression.LogicalOperations.Not, leftTerm, rightTerm);
        }

        public static BinaryExpression Or(this FilterExpression leftTerm, FilterExpression rightTerm)
        {
            return new BinaryExpression(BinaryExpression.LogicalOperations.Or, leftTerm, rightTerm);
        }
    }
}
